using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using PhotoBlenderLib;
using FlickrNet;

namespace BlenderForm {
	public partial class BlenderForm : Form {

		/// <summary>
		/// Form constructor
		/// </summary>
		public BlenderForm() {
			InitializeComponent();

			apikey = ConfigurationManager.AppSettings["apikey"];
            filepath = ConfigurationManager.AppSettings["filepath"];
			log = new List<string>();
			log.Add("Initializing...");
			//files = new List<string>();
		}

		/// <summary>
		/// Search button click event
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void btnSearch_Click(object sender, System.EventArgs e) {
			// disable the search button
			btnSearch.Enabled = false;

			// make sure we have some tags
			if (txtTags.Text.Length <= 0) 
				return;

			// get retrieval values from form fields
			tags = txtTags.Text.Split(Char.Parse(" "));
			filepath = txtDirSource.Text;
			count = (int)this.numPhotos.Value;

			// start thread to retrieve photos
			Thread t = new Thread(new ThreadStart(GetPhotos));
			t.Start();
		}

		/// <summary>
		/// Get the photos
		/// </summary>
		private void GetPhotos() {
			Flickr f = new Flickr(apikey);
			Photos photos = f.PhotosSearch(tags, TagMode.AllTags, "");

			// dont count over the number of photos found
			if (++count > photos.PhotoCollection.Length)
				count = photos.PhotoCollection.Length;

			// loop up to max photo count
			for (int i = 0; i < count; i++) {
				// get the photo
				RetrievePhoto(photos.PhotoCollection[i].MediumUrl);
				// set the current photo
				lock (_lock)
					currentPhoto = i;

				Invoke(new MethodInvoker(UpdateStatus));
				// Sleep a bit
				Thread.Sleep(50);
			}

			Invoke(new MethodInvoker(SearchComplete));
		}


		/// <summary>
		/// Search Complete
		/// </summary>
		private void SearchComplete() {
			MessageBox.Show("Photo Download Complete.", "Download Complete", MessageBoxButtons.OK);
			this.pbProgress.Value = 0;
			btnSearch.Enabled = true;
		}


		/// <summary>
		/// Update status
		/// </summary>
		private void UpdateStatus() {
			lock (_lock) {
				this.pbProgress.Value = (int)(((decimal)currentPhoto / (decimal)count) * 100);
                foreach(string s in log) 
                {
                    lstLog.Items.Add(s);
                }
                lstLog.SetSelected(lstLog.Items.Count - 1, true);
                lstLog.SetSelected(lstLog.Items.Count - 1, false); 
                log.Clear();
			}
		}

		/// <summary>
		/// Get photo from flickr and save it to disk
		/// </summary>
		/// <param name="url">Photo address</param>
		private void RetrievePhoto(string url) {

			// get filename to save photo to
			string filename = string.Concat(filepath, "\\", GetFilename(url));

			// create web client to retrieve photo
			WebClient client = new WebClient();
			// get photo, save to file
			client.DownloadFile(url, filename);

			lock (_lock)
				log.Insert(0, String.Concat("\nDownloading: ", url));

			//files.Add(filename);
		}

		/// <summary>
		/// Determine a filename from the url
		/// </summary>
		/// <param name="url">Photo Url</param>
		/// <returns>Photo Filename</returns>
		private string GetFilename(string url) {
			lock (_lock)
				return currentPhoto.ToString("00") + "photo.jpg";
		}








		/// <summary>
		/// Blend button clicked
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void btnBlend_Click(object sender, System.EventArgs e) {
			
			btnBlend.Enabled = false;
            filepath = txtDirSource.Text;
			this._width = (int)numWidth.Value;
			this._height = (int)numHeight.Value;

			Thread t = new Thread(new ThreadStart(BlendPhotos));
			t.Start();
		}

		/// <summary>
		/// Blend photos
		/// </summary>
		private void BlendPhotos() {

			string path;
            string outputPath;
			int width;
			int height;

			lock (_lock) {
				path = this.filepath;
				width = _width;
				height = _height;
			}

			List<string> files = GetFileList(path);
            outputPath = ConfigurationManager.AppSettings["filepath"];

			Blender blender = new Blender(files, width, height, outputPath);
			blender.BlendPhotos();

			Invoke(new MethodInvoker(BlendComplete));
		}

		/// <summary>
		/// Get File List
		/// </summary>
		/// <param name="path"></param>
		/// <returns></returns>
		private List<string> GetFileList(string path) {
			List<string> files = new List<string>();
			
			DirectoryInfo dir = new DirectoryInfo(path);
			foreach (FileInfo f in dir.GetFiles())
				files.Add(f.FullName);

			return files;
		}

		/// <summary>
		/// Blend Complete
		/// </summary>
		private void BlendComplete() {
			MessageBox.Show("Blending Complete");
			btnBlend.Enabled = true;
		}

		/// <summary>
		/// Set photo source path.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void btnBrowse_Click(object sender, System.EventArgs e) {
			if (txtDirSource.Text.Length > 0 && Directory.Exists(txtDirSource.Text))
				fbdFolder.SelectedPath = txtDirSource.Text;

			DialogResult result = this.fbdFolder.ShowDialog();
			if (result == DialogResult.OK) {
				string newPath = fbdFolder.SelectedPath;
				if (!Directory.Exists(newPath)) {
					MessageBox.Show("Directory does not exist", "Invalid Directory", MessageBoxButtons.OK);
					return;
				}
				txtDirSource.Text = newPath;
			}
		}




		static readonly object _lock = new object();
		string[] tags;
		int count;
		string apikey;
		string filepath;
		int currentPhoto = 0;
		List<string> log;
		int _width = 500;
		int _height = 500;
	}
}